// ++++++++++++++++++++++++++++++++++++++++
// 《零基础Go语言算法实战》源码
// ++++++++++++++++++++++++++++++++++++++++
// Author:廖显东（ShirDon）
// Blog:https://www.shirdon.com/
// Gitee:https://gitee.com/shirdonl/goAlgorithms.git
// Buy link :https://item.jd.com/14101229.html
// ++++++++++++++++++++++++++++++++++++++++

package main

import (
	"fmt"
	"math"
)

func main() {
	// 网页之间的链接矩阵
	links := [][]float64{
		{0, 1, 1},
		{1, 0, 1},
		{1, 1, 0},
	}

	// 阻尼因子，表示点击随机链接的概率
	dampingFactor := 0.85

	// 网页数量
	n := len(links)

	// 将 PageRank 分数初始化为 1/n
	scores := make([]float64, n)
	for i := range scores {
		scores[i] = 1 / float64(n)
	}

	// 迭代直到收敛
	for {
		newScores := make([]float64, n)
		for i := range newScores {
			// 计算此页面的分数
			score := 0.0
			for j := range links {
				if links[j][i] == 1 {
					// 此页面链接到当前页面
					score += scores[j] / float64(countLinks(links[j]))
				}
			}
			// 添加阻尼因子和点击随机链接的概率
			newScores[i] = (1-dampingFactor)/float64(n) + dampingFactor*score
		}
		// 检查收敛
		if scoreDistance(scores, newScores) < 0.0001 {
			break
		}
		scores = newScores
	}

	// 打印最终成绩
	fmt.Println("PageRank 分数:", scores)
}

// 返回链接矩阵给定行中的链接数
func countLinks(row []float64) int {
	count := 0
	for _, value := range row {
		if value == 1 {
			count++
		}
	}
	return count
}

// 返回两个得分向量之间的欧氏距离
func scoreDistance(s1, s2 []float64) float64 {
	distance := 0.0
	for i := range s1 {
		distance += math.Pow(s1[i]-s2[i], 2)
	}
	return math.Sqrt(distance)
}

//$ go run pageRank.go
//PageRank scores: [0.3333333333333333 0.3333333333333333 0.3333333333333333]
